#ifdef OS_WP8

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <wtypes.h>
#include <inaddr.h>
#include <windows.h>
#include <process.h>
#include <eh.h>
#include <glf/wp8/WP8SocketUtils.h>
#include <glf/wp8/WP8Socket.h>
#include <glf/wp8/ThreadEmulation.h>

const int HOST_BUF_LEN = 10;
const int MAX_NUM_SOCKET = 1024;
struct hostent * l_virtual_host[HOST_BUF_LEN];
int l_vhost_count = 0;
CSOCKET** list_wp8_socket = NULL;
int wsa_startup_count = 0;

int checkIpAddressFormat(const char *str)
{
	unsigned int a,b,c,d,e,f,g,h=0;
	unsigned int ret = 0;
    int res = sscanf_s(str,"%d.%d.%d.%d",&a,&b,&c,&d);
	if (res == 4)
		return 1;//IPv4
	res = sscanf_s(str,"%d:%d:%d:%d:%d:%d:%d:%d",&a,&b,&c,&d,&e,&f,&g,&h);
	if (res == 8)
		return 2;//IPv6
	return 0;
}
unsigned int inet_addr(const char *str)
{ 
    unsigned int a,b,c,d=0;
	unsigned int ret = 0;
    int res = sscanf_s(str,"%d.%d.%d.%d",&a,&b,&c,&d);
	if (res < 4)
		return 0;
	ret = (d << 24) | (c << 16) | (b << 8) | a;
	return ret;
}
char *inet_ntoa(in_addr in)
{
	static char iAddr[16] = {0};
	memset(iAddr, 0, 16);
	sprintf_s(iAddr,"%d.%d.%d.%d", in.s_net, in.s_host, in.s_lh, in.s_impno);
	return iAddr;
}
int FD_ISSET(int fd, struct fd_set FAR *set)
{
	if (!set)
		return false;
	for (int i = 0; i < set->fd_count; i++)
	{
		if (fd == set->fd_array[i])
			return true;
	}
	return false;
}

int WSAStartup(WORD  wVersionRequested, LPWSADATA  lpWSAData)
{	
	if (wsa_startup_count == 0)
	{
		IVectorView<HostName^>^ listhost = NetworkInformation::GetHostNames();	
		if (listhost->Size <= 0)
		{
			//return WSASYSNOTREADY;
		}
		for(int i = 0; i< listhost->Size; i++)
		{
			String^ host = listhost->GetAt(i)->DisplayName;
			SOCK_DEBUG_OUT("WP8 IP Address:%s\n", pstos(host).c_str());
		}

		for (int i=0; i<HOST_BUF_LEN; i++ )
		{
			l_virtual_host[i] = NULL;
		}
		l_vhost_count = 0;

		list_wp8_socket = new CSOCKET*[MAX_NUM_SOCKET];
		for (int i = 0; i < MAX_NUM_SOCKET; i++)
		{
			list_wp8_socket[i] = NULL;
		}
	}
	wsa_startup_count++;
	if (wVersionRequested >= MAKEWORD(1, 1))
	{
		lpWSAData->wVersion = wVersionRequested;
		lpWSAData->wHighVersion = MAKEWORD(2, 2);
		return 0;
	}
	return WSAVERNOTSUPPORTED;
}
int WSACleanup(void)
{
	if (wsa_startup_count > 0)
	{
		wsa_startup_count--;
		if (wsa_startup_count==0)
		{
			for ( int i=0; i<l_vhost_count; i++ )
			{
				SOCK_API_DEL( l_virtual_host[i]->h_name );		
				for (int j=0; j<1; j++ )
				{
					SOCK_API_DEL( l_virtual_host[i]->h_addr_list[j] );
					l_virtual_host[i]->h_addr_list[j] = NULL;
				}
				SOCK_API_DEL( l_virtual_host[i]->h_addr_list );
				SOCK_API_DEL( l_virtual_host[i] );
				l_virtual_host[i] = NULL;
			}
			l_vhost_count = 0;

			for (int i = 0; i < MAX_NUM_SOCKET; i++)
			{
				SOCK_API_DEL(list_wp8_socket[i]);
			}
		}
	}
	return 0;
}
int WSAGetLastError(void)
{
	return GetLastError();
}

void WSASetLastError(int iError)
{
	SetLastError(iError);
}

void Sleep(DWORD dwMilliseconds)
{
	ThreadEmulation::Sleep(dwMilliseconds);
}

int setsockopt (int socket, int level, int optname, const char FAR * optval, int optlen){return 0;}
int getsockopt(int socket, int level, int option_name, void *option_value, socklen_t *option_len){return 0;}
int ioctlsocket (int socket, long cmd, u_long FAR *argp){return 0;}
struct protoent* getprotobyname(const char * name)
{
	static struct protoent protocol = {"tcp", NULL, IPPROTO_TCP};
	return &protocol;
}
u_short htons(u_short usnum){
	return (usnum >> 8) | (usnum << 8);
}
u_short ntohs(u_short usnum){
	return htons(usnum);
}
u_long htonl(u_long hostlong){
	return ((((uint32)(hostlong) & 0xff000000) >> 24) | (((uint32)(hostlong) & 0x00ff0000) >> 8) | (((uint32)(hostlong) & 0x0000ff00) << 8) | (((uint32)(hostlong) & 0x000000ff) << 24));
}
u_long ntohl(u_long netlong){
	return htonl(netlong);
}

DWORD WINAPI TranslateHostToIp(void* hostname)
{
	if (hostname && strlen((char*)hostname) <= 0)
		return -1;
	DatagramSocket^ socket = ref new DatagramSocket();
	HANDLE waitForResolver = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
	String^ strHost = atops((char*)hostname);
	task<void>(socket->ConnectAsync(ref new HostName(strHost), "0"))
	.then([socket, waitForResolver, hostname](task<void> previousTask)
	{
		try {
			previousTask.get();
			if (socket->Information && socket->Information->RemoteAddress)
			{
				String^ remoteIp = socket->Information->RemoteAddress->DisplayName;
				strcpy((char*)hostname, pstos(remoteIp).c_str());
			}
		} catch (Exception^ ex) {
		}
		SetEvent(waitForResolver);
	});
	WaitForSingleObjectEx(waitForResolver, 3000, false);
	return 0;
}

struct hostent *gethostbyname(const char *name)
{
	for (int i=0; i<l_vhost_count; i++)
	{
		if ( strcmp( name, l_virtual_host[i]->h_name ) == 0 )
		{
			return l_virtual_host[i];
		}
	}

	if (l_vhost_count < HOST_BUF_LEN)
	{
		if (l_virtual_host[l_vhost_count])
		{
			SOCK_API_DEL (l_virtual_host[l_vhost_count]->h_name);	
			SOCK_API_DEL_ARRAY(l_virtual_host[l_vhost_count]->h_addr_list, 1);
			delete (l_virtual_host[l_vhost_count]);
			l_virtual_host[l_vhost_count] = NULL;
		}

		unsigned int ipAddr = 0;
		if (!strcmp(name, "WP8-Emulator"))
		{
			char WP8Addr[64] = {0};
			IVectorView<HostName^>^ listhost = NetworkInformation::GetHostNames();
			for(int i = 0; i< listhost->Size; i++)
			{
				String^ host = listhost->GetAt(i)->DisplayName;
				if(host != nullptr)
				{
					strcpy(WP8Addr, pstos(host).c_str());			
				}
			}
			ipAddr = inet_addr(WP8Addr);
		}
		else if(!strcmp(name, "::"))
		{
			ipAddr = INADDR_ANY;
		}
		else
		{
			char hostname[256] = {0};
			strcpy(hostname, name);
			HANDLE resolverThread = ThreadEmulation::CreateThread(0, 0, (LPTHREAD_START_ROUTINE)TranslateHostToIp, hostname, 0, 0);
			WaitForSingleObjectEx(resolverThread, 3000, false);
			if (!strcmp(hostname, name))
				return NULL;
			ipAddr = inet_addr(hostname);
		}
		
		l_virtual_host[l_vhost_count] = new struct hostent;
		memset( l_virtual_host[l_vhost_count], 0, sizeof( struct hostent ) );
		l_virtual_host[l_vhost_count]->h_length = 4;
		l_virtual_host[l_vhost_count]->h_addrtype = AF_INET;
		l_virtual_host[l_vhost_count]->h_name = SOCK_API_STRNEW( name );
		l_virtual_host[l_vhost_count]->h_addr_list = new char * [2];		

		int i = 0;
		for (; i<1; i++ )
		{
			//this is a bug, while the ip have 0 (eg. 10.15.0.64 ).we will get 10.15.0.253.
			//l_virtual_host[l_vhost_count]->h_addr_list[i] = 	XP_API_STRNEW( server->h_addr_list[i] );
			
			l_virtual_host[l_vhost_count]->h_addr_list[i] = new char[ 4 ];
			memcpy(l_virtual_host[l_vhost_count]->h_addr_list[i] , &ipAddr, 4 ) ;
		}
		l_virtual_host[l_vhost_count]->h_addr_list[i] = NULL;
		l_vhost_count++;

		return l_virtual_host[l_vhost_count - 1];
	}
	else
	{
		l_vhost_count -- ;
		return gethostbyname( name );
	}
}

struct hostent *gethostbyaddr(const void *addr, int len, int type)
{
	if (type == AF_INET)
	{
		char formatedAddr[4] = {0};
		if (len == 4)
		{
			memcpy(formatedAddr, addr, 4);
			for (int i=0; i<l_vhost_count; i++)
			{
				for (int j=0; j<1; j++ )
				{
					if (strncmp( (char*)formatedAddr, l_virtual_host[i]->h_addr_list[j], 4) == 0)
					{
						return l_virtual_host[i];
					}
				}				
			}
		}
	}
	return NULL;
}

int getpeername(int socket, struct sockaddr FAR* name, int FAR* namelen)
{
	if (socket < 0 || socket >= MAX_NUM_SOCKET || list_wp8_socket[socket]==NULL)
	{
		name = NULL;
		*namelen = 0;
		WSASetLastError(WSAENOTSOCK);
		return SOCKET_ERROR;
	}

	memset(name, 0, sizeof(sockaddr));
	if (list_wp8_socket[socket]->GetRemotePort() != nullptr && list_wp8_socket[socket]->GetRemotePort()->Length() > 0)
	{
		u_short hostPort = atoi(pstos(list_wp8_socket[socket]->GetRemotePort()).c_str());
		((sockaddr_in*)name)->sin_port = htons(hostPort);
	}
	else
		((sockaddr_in*)name)->sin_port = 0;

	if (list_wp8_socket[socket]->GetRemoteHost() != nullptr && list_wp8_socket[socket]->GetRemoteHost()->Length() > 0)
	{
		if (checkIpAddressFormat((char*)pstos(list_wp8_socket[socket]->GetRemoteHost()).c_str()) != 0)
		{
			int iAddr = inet_addr((char*)pstos(list_wp8_socket[socket]->GetRemoteHost()).c_str());
			memcpy(&((sockaddr_in*)name)->sin_addr, &iAddr, 4);
		}
		else
		{
			//RemoteHostName is not in format xxx.xxx.xxx.xxx
			hostent* host = gethostbyname(pstos(list_wp8_socket[socket]->GetRemoteHost()).c_str());
			memcpy(&((sockaddr_in*)name)->sin_addr, host->h_addr_list[0], 4);			
		}
	}
	else
	{
		int unknow_addr = 0;
		memcpy(&((sockaddr_in*)name)->sin_addr, &unknow_addr, 4);
	}
	return 0;
}
int getsockname(int socket, struct sockaddr FAR* name, int FAR* namelen)
{
	if (socket < 0 || socket >= MAX_NUM_SOCKET || list_wp8_socket[socket]==NULL)
	{
		name = NULL;
		*namelen = 0;
		WSASetLastError(WSAENOTSOCK);
		return SOCKET_ERROR;
	}

	memset(name, 0, sizeof(sockaddr));
	int iAddr = 0;
	if (list_wp8_socket[socket]->GetLocalPort() != nullptr && list_wp8_socket[socket]->GetLocalPort()->Length() > 0)
	{
		u_short hostPort = atoi(pstos(list_wp8_socket[socket]->GetLocalPort()).c_str());
		((sockaddr_in*)name)->sin_port = htons(hostPort);
	}
	else
	{
		((sockaddr_in*)name)->sin_port = 0;
	}

	if (list_wp8_socket[socket]->GetLocalHost() != nullptr && list_wp8_socket[socket]->GetLocalHost()->Length() > 0)
	{
		if (checkIpAddressFormat((char*)pstos(list_wp8_socket[socket]->GetLocalHost()).c_str()) != 0)
		{
			int iAddr = inet_addr((char*)pstos(list_wp8_socket[socket]->GetLocalHost()).c_str());
			memcpy(&((sockaddr_in*)name)->sin_addr, &iAddr, 4);
		}
		else
		{
			//LocalHostName is not in format xxx.xxx.xxx.xxx
			hostent* host = gethostbyname(pstos(list_wp8_socket[socket]->GetLocalHost()).c_str());
			memcpy(&((sockaddr_in*)name)->sin_addr, host->h_addr_list[0], 4);			
		}
	} else
	{
		int unkown_addr = 0;
		memcpy(&((sockaddr_in*)name)->sin_addr, &unkown_addr, 4);
	}

	((sockaddr_in*)name)->sin_family = AF_INET;
	*namelen = sizeof(sockaddr_in);
	return 0;
}

int gethostname(char *name, int namelen)
{
	strcpy(name, "WP8-Emulator");
	return 0;
}

int close(int socket)
{
	if (wsa_startup_count <= 0)
	{
		WSASetLastError(WSANOTINITIALISED);
		return SOCKET_ERROR; 
	}

	if (socket < 0 || socket >= MAX_NUM_SOCKET || list_wp8_socket[socket]==NULL)
	{
		WSASetLastError(WSAENOTSOCK);
		return SOCKET_ERROR;
	}

	int iRet = list_wp8_socket[socket]->Close();
	delete list_wp8_socket[socket];
	list_wp8_socket[socket] = NULL;
	return iRet;

}
int closesocket(int socket){return close(socket);}
int shutdown(int socket, int how)
{
	if (socket < 0 || socket >= MAX_NUM_SOCKET || list_wp8_socket[socket]==NULL)
	{
		WSASetLastError(WSAENOTSOCK);
		return SOCKET_ERROR;
	}
	return list_wp8_socket[socket]->Shutdown(how);
}
int connect(int socket, sockaddr* foreignAddress, unsigned int addressLength)
{
	if (socket < 0 || socket >= MAX_NUM_SOCKET || list_wp8_socket[socket]==NULL)
	{
		WSASetLastError(WSAENOTSOCK);
		return SOCKET_ERROR;
	}
	if (!foreignAddress)
	{
		return list_wp8_socket[socket]->Connect(NULL, 0);
	}

	int iRet = 0;
	{
		char *strIp = inet_ntoa(((sockaddr_in*)foreignAddress)->sin_addr);
		u_short netPort = ((sockaddr_in*)foreignAddress)->sin_port;
		iRet = list_wp8_socket[socket]->Connect(strIp, ntohs(netPort));
	}
	return iRet;
}

int sendto(int socket, const char FAR * buf, int len, int flags, const struct sockaddr FAR * foreignAddress, int tolen)
{
	if(socket < 0 || socket >= MAX_NUM_SOCKET || list_wp8_socket[socket]==NULL)
	{
		WSASetLastError(WSAENOTSOCK);
		return SOCKET_ERROR;
	}

	if (!foreignAddress)
	{
		return list_wp8_socket[socket]->SendTo(buf, len, NULL, 0);
	}

	int iRet = 0;
	{
		char *strIp = inet_ntoa(((sockaddr_in*)foreignAddress)->sin_addr);
		u_short netPort = ((sockaddr_in*)foreignAddress)->sin_port;
		iRet = list_wp8_socket[socket]->SendTo(buf, len, strIp, ntohs(netPort));
	}
	return iRet;
}

int send(int socket, const void* msg, unsigned int msgLength, int flags)
{
	if (socket < 0 || socket >= MAX_NUM_SOCKET || list_wp8_socket[socket] == NULL)
	{
		WSASetLastError(WSAENOTSOCK);
		return SOCKET_ERROR;
	}
	return list_wp8_socket[socket]->Send(msg, msgLength);
}

int recvfrom(int socket, char FAR* buf, int len, int flags, struct sockaddr FAR* foreignAddress, int FAR* fromlen)
{
	if (socket < 0 || socket >= MAX_NUM_SOCKET || list_wp8_socket[socket] == NULL)
	{
		WSASetLastError(WSAENOTSOCK);
		return SOCKET_ERROR;
	}

	if (!foreignAddress)
	{
		return list_wp8_socket[socket]->Recv(buf, len);
	}

	char* strIp = NULL;
	char inIp[4] = {0};
	int hostPort = 0;
	int iRet = list_wp8_socket[socket]->RecvFrom(buf, len, &strIp, &hostPort);
	if (iRet <= 0)
		return iRet;

	((sockaddr_in*)foreignAddress)->sin_port = htons(hostPort);	
	if (checkIpAddressFormat(strIp) != 0)
	{
		int inAddr = inet_addr(strIp);
		memcpy(&((sockaddr_in*)foreignAddress)->sin_addr, &inAddr, 4);
	}
	else
	{
		hostent* host = gethostbyname(strIp);
		if (host)
			memcpy(&((sockaddr_in*)foreignAddress)->sin_addr, host->h_addr_list[0], 4);
		else
			memset(&((sockaddr_in*)foreignAddress)->sin_addr, 0, 4);
	}
	SOCK_API_DELETE_ARRAY(strIp);
	return iRet;
}

int recv(int socket, void* recvBuffer, unsigned int bufferLength, int flags)
{
	if (socket < 0 || socket >= MAX_NUM_SOCKET || list_wp8_socket[socket]==NULL)
	{
		WSASetLastError(WSAENOTSOCK);
		return SOCKET_ERROR;
	}
	return list_wp8_socket[socket]->Recv(recvBuffer, bufferLength);
}

int bind(int socket, sockaddr* localAddress, unsigned int addressLength)
{
	if (socket < 0 || socket >= MAX_NUM_SOCKET || list_wp8_socket[socket]==NULL)
	{
		WSASetLastError(WSAENOTSOCK);
		return SOCKET_ERROR;
	}

	if (!localAddress)
	{
		return list_wp8_socket[socket]->Bind("0.0.0.0", 0);
	}

	int iRet = 0;
	{
		char *strIp = inet_ntoa(((sockaddr_in*)localAddress)->sin_addr);
		int hostPort = ntohs(((sockaddr_in*)localAddress)->sin_port);
		iRet = list_wp8_socket[socket]->Bind(strIp, hostPort);
	}

	return iRet;
}
int listen(int socket, int queueLimit)
{
	if (socket < 0 || socket >= MAX_NUM_SOCKET || list_wp8_socket[socket]==NULL)
	{
		WSASetLastError(WSAENOTSOCK);
		return SOCKET_ERROR;
	}
	return list_wp8_socket[socket]->Listen(queueLimit);
}
int accept(int socket, sockaddr* clientAddress, int *addressLength)
{
	if (socket < 0 || socket >= MAX_NUM_SOCKET || list_wp8_socket[socket]==NULL)
	{
		WSASetLastError(WSAENOTSOCK);
		return SOCKET_ERROR;
	}

	int iRet = list_wp8_socket[socket]->Accept();
	if (iRet >= 0 && iRet < MAX_NUM_SOCKET && list_wp8_socket[iRet] != NULL && clientAddress)
	{
		memset(clientAddress, 0, sizeof(sockaddr));
		if (list_wp8_socket[iRet]->GetRemotePort() != nullptr)
		{
			u_short hostPort = atoi(pstos(list_wp8_socket[iRet]->GetRemotePort()).c_str());
			((sockaddr_in*)clientAddress)->sin_port = htons(hostPort);
		}
		else
			((sockaddr_in*)clientAddress)->sin_port = 0;

		if (list_wp8_socket[iRet]->GetRemoteHost() != nullptr)
		{			
			if (checkIpAddressFormat((char*)pstos(list_wp8_socket[iRet]->GetRemoteHost()).c_str()) != 0)
			{
				int iAddr = inet_addr((char*)pstos(list_wp8_socket[iRet]->GetRemoteHost()).c_str());
				memcpy(&((sockaddr_in*)clientAddress)->sin_addr, &iAddr, 4);
			}
			else
			{
				//RemoteHostName is not in format xxx.xxx.xxx.xxx
				hostent* host = gethostbyname(pstos(list_wp8_socket[iRet]->GetRemoteHost()).c_str());
				if (host)
					memcpy(&((sockaddr_in*)clientAddress)->sin_addr, host->h_addr_list[0], 4);
				else
					memcpy(&((sockaddr_in*)clientAddress)->sin_addr, 0, 4);			
			}
		}else{
			memcpy(&((sockaddr_in*)clientAddress)->sin_addr, 0, 4);
		}
	}
	return iRet;
}

int select(int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * exceptfds, const struct timeval FAR * timeout)
{
	if (!readfds && !writefds && !exceptfds)
		return 0;

	fd_set fdsRead;
	FD_ZERO(&fdsRead);
	if (readfds)
	{		
		for (int i = 0; i < readfds->fd_count; i++)
		{
			int fd = readfds->fd_array[i];
			if(fd >= 0 && fd < MAX_NUM_SOCKET && list_wp8_socket[fd] != NULL)
			{
				if (list_wp8_socket[fd]->Select(FD_READ))
				{
					FD_SET(fd, &fdsRead);
				}
			}
		}
		memcpy(readfds, &fdsRead, sizeof(fd_set));
	}

	fd_set fdsWrite;
	FD_ZERO(&fdsWrite);
	if (writefds)
	{		
		for (int i = 0; i < writefds->fd_count; i++)
		{
			int fd = writefds->fd_array[i];
			if(fd >= 0 && fd < MAX_NUM_SOCKET && list_wp8_socket[fd] != NULL)
			{
				if (list_wp8_socket[fd]->Select(FD_WRITE))
				{
					FD_SET(fd, &fdsWrite);
				}
			}
		}
		memcpy(writefds, &fdsWrite, sizeof(fd_set));
	}

	fd_set fdsExcept;
	FD_ZERO(&fdsExcept);
	if (exceptfds)
	{		
		for (int i = 0; i < exceptfds->fd_count; i++)
		{
			int fd = exceptfds->fd_array[i];
			if(fd >= 0 && fd < MAX_NUM_SOCKET && list_wp8_socket[fd] != NULL)
			{
				if (list_wp8_socket[fd]->Select(FD_CONNECT))
				{
					FD_SET(fd, &fdsExcept);
				}
			}
		}
		memcpy(exceptfds, &fdsExcept, sizeof(fd_set));
	}
	
	return fdsWrite.fd_count + fdsRead.fd_count + fdsExcept.fd_count;
}

int socket(int protocolFamily, int type, int protocol)
{
	if (wsa_startup_count <= 0)
	{
		WSASetLastError(WSANOTINITIALISED);
		return SOCKET_ERROR;
	}

	Object^ sock = nullptr;
	if(type == SOCK_STREAM)
	{
		try{
			sock = ref new StreamSocket();
		}catch(Exception^ ex)
		{
			SOCK_DEBUG_OUT("Create TCP Socket error: %s\n", pstos(ex->Message).c_str());
			return -1;
		}
	}
	else
	{
		try{
			sock = ref new DatagramSocket();
		}catch(Exception^ ex)
		{
			SOCK_DEBUG_OUT("Create UDP Socket error: %s\n", pstos(ex->Message).c_str());
			return -1;
		}
	}

	if (sock != nullptr)
	{
		CSOCKET *socket = new CSOCKET(sock,type, false);
		int iRet = 0;
		for (; iRet < MAX_NUM_SOCKET; iRet++)
		{
			if (list_wp8_socket[iRet] == NULL)
				break;
		}

		if (iRet < MAX_NUM_SOCKET)
		{
			list_wp8_socket[iRet] = socket;
			return iRet;
		}	
		delete socket;
	}
	WSASetLastError(WSAEMFILE);
	return SOCKET_ERROR;	
}

HRESULT SockStatusToWSAError(SocketErrorStatus status)
{
	switch (status)
	{
	case SocketErrorStatus::AddressAlreadyInUse:
		return WSAEADDRINUSE;
	case SocketErrorStatus::AddressFamilyNotSupported:
		return WSAEAFNOSUPPORT;
	case SocketErrorStatus::CannotAssignRequestedAddress:
		return WSAEADDRNOTAVAIL;
	case SocketErrorStatus::ConnectionRefused:
		return WSAECONNREFUSED;
	case SocketErrorStatus::ConnectionResetByPeer:
		return WSAENETRESET;
	case SocketErrorStatus::ConnectionTimedOut:
		return WSAETIMEDOUT;
	case SocketErrorStatus::HostIsDown:
		return WSAEHOSTDOWN;
	case SocketErrorStatus::HostNotFound:
		return WSAHOST_NOT_FOUND;
	case SocketErrorStatus::MessageTooLong:
		return WSAEMSGSIZE;
	case SocketErrorStatus::NetworkDroppedConnectionOnReset:
		return WSAENETRESET;
	case SocketErrorStatus::NetworkIsDown:
		return WSAENETDOWN;
	case SocketErrorStatus::NetworkIsUnreachable:
		return WSAENETUNREACH;
	case SocketErrorStatus::NoAddressesFound:
		return WSAENOTCONN;
	case SocketErrorStatus::OperationAborted:
		return ERROR_OPERATION_ABORTED;
	case SocketErrorStatus::SocketTypeNotSupported:
		return WSAESOCKTNOSUPPORT;
	case SocketErrorStatus::TooManyOpenFiles:
		return WSAEMFILE;
	case SocketErrorStatus::SoftwareCausedConnectionAbort:
		return WSAECONNABORTED;
	case SocketErrorStatus::UnreachableHost:
		return WSAEHOSTUNREACH;	
	case SocketErrorStatus::Unknown:
	default:
		return 0;
	}
}

CSOCKET::CSOCKET(Object^ sock, int type, bool connected):
	m_sock(sock),
	m_type(type),
	m_dtWriter(nullptr),
	m_dtReader(nullptr),
	m_localHost(nullptr),
	m_localPort(nullptr),
	m_RemoteHost(nullptr),
	m_RemotePort(nullptr),
	m_listenerCtx(nullptr),
	m_sizeQueueConn(3),
	m_dgram_msg_mutex(NULL),
	m_isListening(false),
	ConnectionState(CONNECT_STATE_NONE),
	m_BufferSizeInQueueDgram(0)
{
	if (m_sock != nullptr)
	{
		if ((m_type & SOCK_STREAM) && connected)
		{
			ConnectionState = CONNECT_STATE_SUCCESS;
			m_dtWriter = ref new DataWriter(((StreamSocket^)m_sock)->OutputStream);
			m_dtReader = ref new DataReader(((StreamSocket^)m_sock)->InputStream);
			m_dtReader->InputStreamOptions = InputStreamOptions::Partial;
			
			task<unsigned int>(m_dtReader->LoadAsync(MAX_PACKET_SIZE),m_recvTaskTokenSource.get_token())
			.then([this](task<unsigned int> loadTask)
			{
				try 
				{ 
					// Try getting an exception. 
					unsigned int actualLen = loadTask.get();
				} 
				catch (Exception^ exception) 
				{
					ConnectionState = CONNECT_STATE_FAILED;
					WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(exception->HResult)));
					SOCK_DEBUG_OUT("Recv failed with error: %ls", exception->Message->Data());
				}
			});				
		}
	}	
}

CSOCKET::~CSOCKET()
{
	Close();
}

int CSOCKET::Close()
{
	if (m_sock != nullptr)
	{
		m_bindTaskTokenSource.cancel();
		m_connectTaskTokenSource.cancel();
		m_sock = nullptr;
	}
	if (m_dtReader != nullptr)
	{
		m_recvTaskTokenSource.cancel();
		m_dtReader = nullptr;		
	}
	if (m_dtWriter != nullptr)
	{
		m_sendTaskTokenSource.cancel();
		m_dtWriter = nullptr;		
	}
	if (m_listenerCtx)
	{
		m_listenerCtx = nullptr;
	}

	if (m_queueConn.size() > 0)
		m_queueConn.clear();
	if (m_queueDgramMsg.size() > 0)
		m_queueDgramMsg.clear();
	if(m_dgram_msg_mutex)
	{	
		ReleaseMutex(m_dgram_msg_mutex);
		CloseHandle(m_dgram_msg_mutex);		
		m_dgram_msg_mutex = NULL;
	}

	return 0;
}

int CSOCKET::Shutdown(int how)
{
	switch(how)
	{
	case 0://SD_RECEIVE
		break;
	case 1://SD_SEND
		break;
	case 2://SD_BOTH
	default://SD_BOTH

		break;
	}
	return 0;
}

int CSOCKET::Bind(char* host, int port)
{
	m_localHost = atops(host);
	if (port > 0)
		m_localPort = port.ToString();
	else
		m_localPort = "";

	if(m_type == SOCK_DGRAM)
	{
		// Start listen operation.
		if (m_listenerCtx == nullptr)
		{
			if (m_dgram_msg_mutex == NULL)
				m_dgram_msg_mutex = CreateMutexEx(NULL, NULL, 0, MUTEX_ALL_ACCESS);
			m_listenerCtx = ref new ListenerContext(this); 
			((DatagramSocket^)m_sock)->MessageReceived += ref new TypedEventHandler<DatagramSocket^, DatagramSocketMessageReceivedEventArgs^>(m_listenerCtx, &ListenerContext::OnMessageRecv);
		}

		HostName^ localhost = nullptr;
		if (m_localHost != "0.0.0.0")
			localhost = ref new HostName(m_localHost);

		try {
			task<void>(((DatagramSocket^)m_sock)->BindEndpointAsync(localhost, m_localPort), m_bindTaskTokenSource.get_token()).get();
			if (((DatagramSocket^)m_sock)->Information != nullptr)
			{
				if (((DatagramSocket^)m_sock)->Information->LocalAddress != nullptr)
					m_localHost = ((DatagramSocket^)m_sock)->Information->LocalAddress->DisplayName;
				m_localPort = ((DatagramSocket^)m_sock)->Information->LocalPort;
			}									

			SOCK_DEBUG_OUT("UDP listening in local port: %s\n", pstos(((DatagramSocket^)m_sock)->Information->LocalPort).c_str()); 
		}
		catch (Exception^ exception) 
		{
			WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(exception->HResult)));
			SOCK_DEBUG_OUT("Start listening failed with error: %s\n", pstos(exception->Message).c_str()); 
		} 
	}

	return port;
}

void CSOCKET::AddQueueConnection(StreamSocket^ clientSock)
{
	if (m_queueConn.size() >= m_sizeQueueConn && !m_isListening)
	{
		delete clientSock;
		return;
	}
	
	m_queueConn.push_back(clientSock);
}
void CSOCKET::AddQueueMessage(DatagramSocketMessageReceivedEventArgs^ clientEvent)
{
	DWORD dwWaitResult = WaitForSingleObjectEx(m_dgram_msg_mutex,INFINITE, false);

	try{
		if (m_BufferSizeInQueueDgram < MAX_DGRAM_BUFFER_SIZE) {
			DataReader^ dtReader = clientEvent->GetDataReader();

			DatagramMessage^ dgramMessage = ref new DatagramMessage();	
			dgramMessage->Data = ref new Array<unsigned char>(dtReader->UnconsumedBufferLength);
			dgramMessage->UnconsumedBufferLength = dtReader->UnconsumedBufferLength;

			dtReader->ReadBytes(dgramMessage->Data);
			m_BufferSizeInQueueDgram += dgramMessage->UnconsumedBufferLength;
			dgramMessage->LocalAddr = clientEvent->LocalAddress->DisplayName;
			dgramMessage->RemoteAddr = clientEvent->RemoteAddress->DisplayName;
			dgramMessage->RemotePort = clientEvent->RemotePort;	

			m_queueDgramMsg.push_back(dgramMessage);
		}
	} catch (Exception^ ex)
	{
		SocketErrorStatus status = SocketError::GetStatus(ex->HResult);
		SOCK_DEBUG_OUT("Start listening failed with error: %s\n", pstos(ex->Message).c_str()); 
	}

	ReleaseMutex(m_dgram_msg_mutex);
}

String^ CSOCKET::GetRemotePort()
{
	if (m_type == SOCK_DGRAM)
	{
		DatagramSocket^ dgSock = (DatagramSocket^)m_sock;
		if (dgSock->Information != nullptr)
			return dgSock->Information->RemotePort;
	} else if (!(m_type & SOCK_SERV))
	{
		StreamSocket^ strSock = (StreamSocket^)m_sock;
		if (strSock->Information != nullptr)
			return strSock->Information->RemotePort;
	}	
	return nullptr;
}
String^ CSOCKET::GetRemoteHost()
{
	if (m_type == SOCK_DGRAM)
	{
		DatagramSocket^ dgSock = (DatagramSocket^)m_sock;
		if (dgSock->Information != nullptr && dgSock->Information->RemoteAddress != nullptr)
			return dgSock->Information->RemoteAddress->DisplayName;
	}else if (!(m_type & SOCK_SERV))
	{
		StreamSocket^ strSock = (StreamSocket^)m_sock;
		if (strSock->Information != nullptr && strSock->Information->RemoteAddress != nullptr)
			return strSock->Information->RemoteAddress->DisplayName;
	}		
	return nullptr;
}

String^ CSOCKET::GetLocalPort()
{
	if( m_type == SOCK_DGRAM)
	{
		DatagramSocket^ dgSock = (DatagramSocket^)m_sock;
		if (dgSock->Information != nullptr)
			return dgSock->Information->LocalPort;
	}else
	{
		if (m_type & SOCK_SERV)
		{
			StreamSocketListener^ strSock = (StreamSocketListener^)m_sock;
			if (strSock->Information != nullptr)
				return strSock->Information->LocalPort;
		}else
		{
			StreamSocket^ strSock = (StreamSocket^)m_sock;
			if (strSock->Information != nullptr)
				return strSock->Information->LocalPort;
		}	
	}
	return nullptr;
}

String^ CSOCKET::GetLocalHost()
{
	if (m_type == SOCK_DGRAM)
	{
		DatagramSocket^ dgSock = (DatagramSocket^)m_sock;
		if (dgSock->Information != nullptr)
		{
			if(dgSock->Information->LocalAddress)
				return dgSock->Information->LocalAddress->DisplayName;
		}
	} else
	{
		if (m_type & SOCK_SERV)
		{
			return m_localHost;
		} else
		{
			StreamSocket^ strSock = (StreamSocket^)m_sock;
			if (strSock->Information != nullptr)
			{
				if (strSock->Information->LocalAddress)
					return strSock->Information->LocalAddress->DisplayName;
			}
		}		
	}
	return nullptr;
}

int CSOCKET::Select(int op)
{
	if (op & FD_READ)
	{
		switch (m_type)
		{
		case SOCK_DGRAM:
			return (m_queueDgramMsg.size() > 0);
			break;
		case SOCK_STREAM:
			return (m_dtReader != nullptr && m_dtReader->UnconsumedBufferLength > 0);
			break;
		case (SOCK_STREAM|SOCK_SERV):
			return (m_queueConn.size() > 0);
			break;
		}		
	}

	if (op & FD_CONNECT)
	{
		if (m_type & SOCK_SERV)
			return (m_queueConn.size() > 0);
		else
			return (ConnectionState == CONNECT_STATE_FAILED);
	}

	if (op & FD_WRITE)
	{
		return ((m_dtWriter != nullptr && m_dtWriter->UnstoredBufferLength == 0) || (m_type == SOCK_DGRAM && m_dtWriter == nullptr));
	}

	return 0;
}

int CSOCKET::Listen(int size_queue)
{
	m_sizeQueueConn = size_queue;
	if (m_type == SOCK_STREAM)
	{
		m_isListening = false;
		Close();
		m_sock = ref new StreamSocketListener();
		m_type = SOCK_STREAM|SOCK_SERV;
		try{
			// Start listen operation.
			m_isListening = false;
			m_listenerCtx = ref new ListenerContext(this); 
			((StreamSocketListener^)m_sock)->ConnectionReceived += ref new TypedEventHandler<StreamSocketListener^, StreamSocketListenerConnectionReceivedEventArgs^>(m_listenerCtx, &ListenerContext::OnConnection);

			HostName^ localhost = nullptr;
			if (m_localHost != "0.0.0.0")
				localhost = ref new HostName(m_localHost);

			task<void>(((StreamSocketListener^)m_sock)->BindEndpointAsync(localhost, m_localPort), m_bindTaskTokenSource.get_token()).then([this] (task<void> previousTask) 
			{ 
				try 
				{ 
					// Try getting all exceptions from the continuation chain above this point.
					previousTask.get();
					if (((StreamSocketListener^)m_sock)->Information != nullptr)
						m_localPort = ((StreamSocketListener^)m_sock)->Information->LocalPort;
					m_isListening = true;
					SOCK_DEBUG_OUT("Bound to local port: %s\n", pstos(((StreamSocketListener^)m_sock)->Information->LocalPort).c_str()); 
				} 
				catch (Exception^ exception) 
				{
					WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(exception->HResult)));
					SOCK_DEBUG_OUT("Bind to localIp[%s], localPort[%s] failed with error: %s\n", pstos(m_localHost).c_str(), pstos(m_localPort).c_str(), pstos(exception->Message).c_str()); 
				} 
			}); 
		}catch(Exception^ ex){
			WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(ex->HResult)));
			SOCK_DEBUG_OUT("Start listening failed with error: %s\n", pstos(ex->Message).c_str()); 
			return SOCKET_ERROR;
		}
	} else {
		SOCK_DEBUG_OUT("Couldn't listen on an UDP socket / a TCP socket that don't bind yet"); 
		return SOCKET_ERROR;
	}
	return 0;
}

int CSOCKET::Accept()
{
	if (m_queueConn.size() <= 0 || !m_isListening)
		return -1;

	CSOCKET *socket = new CSOCKET( m_queueConn.front(), SOCK_STREAM, true);
	m_queueConn.erase(m_queueConn.begin());
	int iRet = 0;
	for (; iRet < MAX_NUM_SOCKET; iRet++)
	{
		if (list_wp8_socket[iRet] == NULL)
			break;
	}
	if (iRet < MAX_NUM_SOCKET)
	{
		list_wp8_socket[iRet] = socket;
		return iRet;
	}
	delete socket;
	WSASetLastError(WSAEMFILE);
	return -1;
}

int CSOCKET::Connect(char* server_name, int port)
{
	if (m_sock == nullptr)
	{
		WSASetLastError(WSAENOTSOCK);
		return SOCKET_ERROR;
	}

	//attempt connection to server	
	if (m_type & SOCK_STREAM)
	{
		if (server_name == NULL)
		{
			WSASetLastError(WSAEAFNOSUPPORT);
			return SOCKET_ERROR;
		}
		if (m_type & SOCK_SERV)
		{
			Close();
			m_sock = ref new StreamSocket();
			m_type = SOCK_STREAM;
		}
		if (ConnectionState == CONNECT_STATE_SUCCESS)
		{
			WSASetLastError(WSAEISCONN);
			return SOCKET_ERROR;
		}
		if (ConnectionState == CONNECT_STATE_WAITING)
		{
			WSASetLastError(WSAEALREADY);
			return SOCKET_ERROR;
		}

		String^ strServerName = atops(server_name);
		try{
			ConnectionState = CONNECT_STATE_WAITING;
			task<void>(((StreamSocket^)m_sock)->ConnectAsync(ref new HostName(strServerName), port.ToString(), SocketProtectionLevel::PlainSocket), m_connectTaskTokenSource.get_token()).then([this] (task<void> previousTask) 
			{ 
				try 
				{ 
					// Try getting all exceptions from the continuation chain above this point. 
					previousTask.get();
					if (((StreamSocket^)m_sock)->Information != nullptr)
					{
						if (((StreamSocket^)m_sock)->Information->LocalAddress != nullptr)
							m_localHost = ((StreamSocket^)m_sock)->Information->LocalAddress->DisplayName;
						m_localPort = ((StreamSocket^)m_sock)->Information->LocalPort;
					}	
					ConnectionState = CONNECT_STATE_SUCCESS;

					m_dtWriter = ref new DataWriter(((StreamSocket^)m_sock)->OutputStream);
					m_dtReader = ref new DataReader(((StreamSocket^)m_sock)->InputStream);
					m_dtReader->InputStreamOptions = InputStreamOptions::Partial;
					task<unsigned int>(m_dtReader->LoadAsync(MAX_PACKET_SIZE),m_recvTaskTokenSource.get_token())
					.then([this](task<unsigned int> loadTask)
					{
						try 
						{ 
							// Try getting an exception.
							unsigned int actualLen = loadTask.get();
							unsigned int unreadSize = m_dtReader->UnconsumedBufferLength;
							int xxx = 0;
						} 
						catch (Exception^ exception) 
						{
							ConnectionState = CONNECT_STATE_FAILED;
							WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(exception->HResult)));
							SOCK_DEBUG_OUT("Recv failed with error: %ls", exception->Message->Data());
						}
					});						
				} 
				catch (Exception^ exception) 
				{
					ConnectionState = CONNECT_STATE_FAILED;
					WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(exception->HResult)));
					SOCK_DEBUG_OUT( "TCP CSOCKET::Connect(): errmsg(%s)\n", pstos(exception->Message).c_str());
				} 
			});			
		}catch(Exception^ ex){
			ConnectionState = CONNECT_STATE_FAILED;
			SOCK_DEBUG_OUT("Connect failed with error: %s\n", pstos(ex->Message).c_str()); 
			WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(ex->HResult)));
			return SOCKET_ERROR;
		}
	} else if (m_type & SOCK_DGRAM)
	{
		if (server_name == NULL)
		{
			ConnectionState = CONNECT_STATE_NONE;
			return 0;
		}
		if (ConnectionState == CONNECT_STATE_WAITING)
		{
			WSASetLastError(WSAEALREADY);
			return SOCKET_ERROR;
		}

		String^ strServerName = atops(server_name);
		try{
			ConnectionState = CONNECT_STATE_WAITING;	
			IOutputStream^ stream = task<IOutputStream^>(((DatagramSocket^)m_sock)->GetOutputStreamAsync(ref new HostName(strServerName), port.ToString())).get();
			if (stream)
			{
				m_dtWriter = ref new DataWriter(stream);
				ConnectionState = CONNECT_STATE_SUCCESS;
			}
		}catch(Exception^ ex){
			ConnectionState = CONNECT_STATE_FAILED;
			SOCK_DEBUG_OUT("Connect failed with error: %s\n", pstos(ex->Message).c_str()); 
			WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(ex->HResult)));
			return SOCKET_ERROR;
		}
		return SOCKET_ERROR;
	}
	WSASetLastError(WSAEWOULDBLOCK);
	return SOCKET_ERROR;
}

int CSOCKET::Send(const void* msg, unsigned int msgLength)
{
	if (!msg || msgLength <= 0 || !Select(FD_WRITE))
		return 0;

	if (m_type == SOCK_STREAM)
	{
		if (ConnectionState != CONNECT_STATE_SUCCESS)
		{
			WSASetLastError(WSAENOTCONN);
			return SOCKET_ERROR;
		}

		Array<unsigned char>^ sendBuff = ref new Array<unsigned char>(msgLength);
		memcpy(sendBuff->Data, msg, msgLength);
		m_dtWriter->WriteBytes(sendBuff);		

		try {
			task<unsigned int>(m_dtWriter->StoreAsync(), m_sendTaskTokenSource.get_token()).then([this, msgLength] (task<unsigned int> writeTask) 
			{ 
				try 
				{ 
					// Try getting an exception.
					unsigned int iResult = writeTask.get();
					if (iResult != msgLength)
					{
						SOCK_DEBUG_OUT("Send failed with error: [Sent=%d][Expected=%d]",iResult,msgLength);
					}
				} 
				catch (Exception^ exception) 
				{
					WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(exception->HResult)));
					SOCK_DEBUG_OUT("Send failed with error: %s", pstos(exception->Message).c_str());
				} 
			});
			return msgLength;
		} catch (Exception^ exception)
		{
			WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(exception->HResult)));
			SOCK_DEBUG_OUT("Send failed with error: %s", pstos(exception->Message).c_str());
		}
	} else if (m_type == SOCK_DGRAM)
	{
		if (msgLength > MAX_PACKET_SIZE)
		{
			WSASetLastError(WSAEMSGSIZE);
			return SOCKET_ERROR;
		}

		if (ConnectionState != CONNECT_STATE_SUCCESS)
		{
			WSASetLastError(WSAENOTCONN);
			return SOCKET_ERROR;
		}

		Array<unsigned char>^ sendBuff = ref new Array<unsigned char>(msgLength);
		memcpy(sendBuff->Data, msg, msgLength);
		m_dtWriter->WriteBytes(sendBuff);		

		try {
			task<unsigned int>(m_dtWriter->StoreAsync(), m_sendTaskTokenSource.get_token()).then([this, msgLength] (task<unsigned int> writeTask) 
			{ 
				try 
				{ 
					// Try getting an exception.
					unsigned int iResult = writeTask.get();
					if (iResult != msgLength)
					{
						SOCK_DEBUG_OUT("Send failed with error: [Sent=%d][Expected=%d]",iResult,msgLength);
					}
				} 
				catch (Exception^ exception) 
				{
					WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(exception->HResult)));
					SOCK_DEBUG_OUT("Send failed with error: %s", pstos(exception->Message).c_str());
				} 
			});
			return msgLength;
		} catch (Exception^ exception)
		{
			WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(exception->HResult)));
			SOCK_DEBUG_OUT("Send failed with error: %s", pstos(exception->Message).c_str());
		}
	}
	return 0;
}

int CSOCKET::SendTo(const void* msg, unsigned int msgLength, char* host, int port)
{
	if (msgLength > MAX_PACKET_SIZE)
	{
		WSASetLastError(WSAEMSGSIZE);
		return SOCKET_ERROR;
	}

	if (!msg || msgLength <= 0 || !Select(FD_WRITE))
		return 0;


	if(m_type == SOCK_STREAM)
	{
		return Send(msg, msgLength);
	}
	else
	{
		if (!host)
		{
			WSASetLastError(WSAEADDRNOTAVAIL);
			return SOCKET_ERROR;
		}

		if (!Select(FD_WRITE))
		{
			WSASetLastError(WSAENOBUFS);
			return SOCKET_ERROR;
		}

		if (ConnectionState == CONNECT_STATE_WAITING)
		{
			WSASetLastError(WSAEWOULDBLOCK);
			return SOCKET_ERROR;
		}
		
		String^ strServerName = atops(host);
		int iRet = 0;

		if(strServerName != m_RemoteHost || port.ToString() != m_RemotePort || ConnectionState != CONNECT_STATE_SUCCESS)
		{					
			m_RemoteHost = strServerName;
			m_RemotePort = port.ToString();
			try {
				ConnectionState = CONNECT_STATE_WAITING;		
				IOutputStream^ stream = task<IOutputStream^>(((DatagramSocket^)m_sock)->GetOutputStreamAsync(ref new HostName(strServerName), port.ToString())).get();
				if (stream)
				{
					m_dtWriter = ref new DataWriter(stream);
					ConnectionState = CONNECT_STATE_SUCCESS;
				}
			} catch (Exception^ exception)
			{
				m_dtWriter = nullptr;
				ConnectionState = CONNECT_STATE_FAILED;
				WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(exception->HResult)));
				SOCK_DEBUG_OUT("Send failed with error: %s", pstos(exception->Message).c_str());
			}
			iRet = 0;
		}

		if(strServerName == m_RemoteHost && port.ToString() == m_RemotePort && ConnectionState == CONNECT_STATE_SUCCESS)
		{
			Array<unsigned char>^ sendBuff = ref new Array<unsigned char>(msgLength);
			memcpy(sendBuff->Data, msg, msgLength);

			try {
				m_dtWriter->WriteBytes(sendBuff);
				task<unsigned int>(m_dtWriter->StoreAsync(), m_sendTaskTokenSource.get_token()).then([this, msgLength] (task<unsigned int> writeTask) 
				{ 
					try 
					{ 
						// Try getting an exception.
						unsigned int iResult = writeTask.get();
						if (iResult != msgLength)
						{
							m_dtWriter = nullptr;
							SOCK_DEBUG_OUT("Send failed with error: [Sent=%d][Expected=%d]",iResult,msgLength);
						}
					} 
					catch (Exception^ exception) 
					{
						m_dtWriter = nullptr;
						ConnectionState = CONNECT_STATE_FAILED;
						WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(exception->HResult)));
						SOCK_DEBUG_OUT("Send failed with error: %s", pstos(exception->Message).c_str());
					} 
				});
			} catch(Exception^ exception)
			{
				m_dtWriter = nullptr;
				ConnectionState = CONNECT_STATE_FAILED;
				WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(exception->HResult)));
				SOCK_DEBUG_OUT("Send failed with error: %s", pstos(exception->Message).c_str());
			}
			iRet = msgLength;
		}
		return iRet;	
	}
	return 0;
}

int CSOCKET::Recv(void* recvBuffer, unsigned int bufferLength)
{
	if (m_type == SOCK_STREAM)
	{
		int iRet = 0;
		if (ConnectionState != CONNECT_STATE_SUCCESS)
		{
			WSASetLastError(WSAENOTCONN);
			return SOCKET_ERROR;
		}

		if (Select(FD_READ))
		{			
			Array<unsigned char>^ recvBuff = nullptr;
			if(bufferLength <= m_dtReader->UnconsumedBufferLength)
				recvBuff = ref new Array<unsigned char>(bufferLength);
			else
				recvBuff = ref new Array<unsigned char>(m_dtReader->UnconsumedBufferLength);

			m_dtReader->ReadBytes(recvBuff);	
			memcpy(recvBuffer, recvBuff->Data, recvBuff->Length);
			iRet = recvBuff->Length;			

			if (m_dtReader->UnconsumedBufferLength <= 0)
			{	
				try {
					m_dtReader->InputStreamOptions = InputStreamOptions::Partial;
					task<unsigned int>(m_dtReader->LoadAsync(MAX_PACKET_SIZE),m_recvTaskTokenSource.get_token())
					.then([this](task<unsigned int> loadTask)
					{
						try 
						{ 
							// Try getting an exception. 
							unsigned int actualLen = loadTask.get();
						} 
						catch (Exception^ exception) 
						{
							ConnectionState = CONNECT_STATE_FAILED;
							WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(exception->HResult)));
							SOCK_DEBUG_OUT("Recv failed with error: %ls", exception->Message->Data());
						}
					});
				} catch(Exception^ ex) {
					WSASetLastError(SockStatusToWSAError(SocketError::GetStatus(ex->HResult)));
					SOCK_DEBUG_OUT("Recv failed with error: %ls", ex->Message->Data());
					return SOCKET_ERROR;
				}

				if(iRet <= 0)
				{
					recvBuffer = NULL;
					WSASetLastError(WSAEWOULDBLOCK);
					return SOCKET_ERROR;
				}
			}
			return iRet;
		}
		WSASetLastError(WSAEWOULDBLOCK);
		return SOCKET_ERROR;
	} else if (m_type == SOCK_DGRAM)
	{
		if (ConnectionState != CONNECT_STATE_SUCCESS)
		{
			WSASetLastError(WSAENOTCONN);
			return SOCKET_ERROR;
		}
		return RecvFrom(recvBuffer, bufferLength, NULL, NULL);
	}
	return 0;
}

int CSOCKET::RecvFrom(void* recvBuffer, unsigned int bufferLength, char**ip, int *port)
{
	if (m_type == SOCK_STREAM)
	{
		if (port!=NULL)
		{
			(*ip) = SOCK_API_STRNEW(pstos(GetRemoteHost()).c_str());
			(*port) = atoi(pstos(GetRemotePort()).c_str());
		}
		return Recv(recvBuffer, bufferLength);
	} else if (m_type == SOCK_DGRAM)
	{
		int readLen = 0;
		DWORD dwWaitResult = WaitForSingleObjectEx(m_dgram_msg_mutex,INFINITE, false);
		//__try {
			if (Select(FD_READ) && m_queueDgramMsg.front() != nullptr)
			{			
				DatagramMessage^ dgramMsg = m_queueDgramMsg.front();
				int currPos = dgramMsg->Data->Length - dgramMsg->UnconsumedBufferLength;			
				if(bufferLength <= dgramMsg->UnconsumedBufferLength)
					readLen = bufferLength;				
				else
					readLen = dgramMsg->UnconsumedBufferLength;

				memcpy(recvBuffer, dgramMsg->Data->Data+currPos, readLen);			
				String^ remoteHost = dgramMsg->RemoteAddr;
				String^ remotePort = dgramMsg->RemotePort;

				dgramMsg->UnconsumedBufferLength -= readLen;
				m_BufferSizeInQueueDgram -= readLen;
				if(dgramMsg->UnconsumedBufferLength <= 0)
					m_queueDgramMsg.erase(m_queueDgramMsg.begin());

				if (port!=NULL)
				{
					if (remoteHost != nullptr && remoteHost->Length() > 0)
						(*ip) = SOCK_API_STRNEW(pstos(remoteHost).c_str());

					if (remotePort != nullptr && remotePort->Length() > 0)
						(*port) = atoi(pstos(remotePort).c_str());			
				}
			}
			else
			{
				recvBuffer = NULL;
				if (port!=NULL)
				{
					*ip = NULL;
					*port = 0;
				}
			}
		//}

		//__finally {
			ReleaseMutex(m_dgram_msg_mutex);
		//}
		if (readLen == 0)
		{
			WSASetLastError(WSAEWOULDBLOCK);
			return SOCKET_ERROR;
		}
		return readLen;
	}

	if (port!=NULL)
	{
		*ip = NULL;
		*port = 0;
	}
	return 0;
}

void ListenerContext::OnConnection(StreamSocketListener^ listener, StreamSocketListenerConnectionReceivedEventArgs^ object) 
{
	EnterCriticalSection(&lock);
	m_listener->AddQueueConnection(object->Socket);
	LeaveCriticalSection(&lock);
}

void ListenerContext::OnMessageRecv(DatagramSocket^ listener, DatagramSocketMessageReceivedEventArgs^ object) 
{
	EnterCriticalSection(&lock);
	m_listener->AddQueueMessage(object);
	LeaveCriticalSection(&lock);
}

#endif // OS_WP8

